//
//  RunLoopViewcontroller.m
//  iOSCodeLearning
//
//  Created by TFAppleWork-Summer on 2017/12/26.
//  Copyright © 2017年 Ace. All rights reserved.
//

#import "RunLoopViewcontroller.h"
#import "NSTimer+Ex.h"
@interface RunLoopViewcontroller ()<UITextViewDelegate>
@property(nonatomic,strong) UITextView *textView;

@property (nonatomic, weak) NSTimer *timer;

@property (nonatomic, strong,getter=getNewString) NSString *newString;

@end

@implementation RunLoopViewcontroller

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"RunLoop";
    self.view.backgroundColor = [UIColor whiteColor];
    // 有关于NSTimer的循环引用问题
    [self p_TimerBlock];
    
    
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//     [self p_RunLoopWithThread];
//      [self p_RunLoopMode];
//    [self p_RunLoopObserverRef];
//    [self p_stopTimer];
    
   
    
    
}

-(void)p_TimerBlock{
    

    
    // 不管控制器有没有强引用timer 都会产生循环引用
    // 1 这种方式创建的timer repeats=yes ,会产生循环引用,需要在viewWillDisappear 的时候将timer 失效，设置为nil
//    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5
//                                                  target:self
//                                                selector:@selector(test)
//                                                userInfo:nil
//                                                 repeats:YES];
    
    // 2 这种方式创建，如果block  里面引用了self还是会循环引用
    /*
     a __weakself
     b viewwillapperar  设置timer失效 设置为nil
     */
//    __weak RunLoopViewcontroller * weakSelf = self;
//    self.timer= [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
//         NSLog(@"block 创建的timer%@",self);
//    }];
    
//    self.timer = [NSTimer cc_scheduledTimerWithTimeInterval:0.5 repeats:YES block:^{
//
//        NSLog(@"timer 分类创建timer");
//    }];
    
}

-(void)test{
    NSLog(@"taget 创建的timer");
}

//- (void)viewWillDisappear:(BOOL)animated{
//    [self.timer invalidate];
//    self.timer = nil;
//}

-(void)dealloc{
    
    [self.timer invalidate];
    self.timer = nil;
    NSLog(@"---------%@----------",NSStringFromClass([self class]));
    
}



-(void)p_RunLoopObserverRef{
    
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"000~~~~~~~~~~");
    }];
    // textView 正在滚动的时候当前runloop对的运行模式是UITackingRunLoopMode 所以要将timer添加到这个mode中
    [[NSRunLoop currentRunLoop] addTimer:timer forMode: UITrackingRunLoopMode];

    
    // 1 创建监听者

    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), // 如何分配存储控件
                                                                       kCFRunLoopAllActivities, // 需要监听的状态
                                                                       YES,                     // 是否持续监听
                                                                       0,                       // 优先级
                                                                       ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
                                                                           // 当监听状态改变时会进入下面的回调
                                                                           /*
                                                                            kCFRunLoopEntry = (1UL << 0),        即将进入runloop
                                                                            kCFRunLoopBeforeTimers = (1UL << 1), 即将处理timer事件
                                                                            kCFRunLoopBeforeSources = (1UL << 2),即将处理sources事件
                                                                            kCFRunLoopBeforeWaiting = (1UL << 5),即将进入睡眠
                                                                            kCFRunLoopAfterWaiting = (1UL << 6), 被唤醒
                                                                            kCFRunLoopExit = (1UL << 7),         runloop退出
                                                                            kCFRunLoopAllActivities = 0x0FFFFFFFU所有状态
                                                                            */
                                                                           
                                                                           switch (activity) {
                                                                               case kCFRunLoopEntry:
                                                                               {
                                                                                   NSLog(@"即将进入runloop");
                                                                               }
                                                                                   break;
                                                                               case kCFRunLoopBeforeTimers:
                                                                               {
                                                                                   NSLog(@"即将处理timer事件");
                                                                               }
                                                                                   break;

                                                                               case kCFRunLoopBeforeSources:
                                                                               {
                                                                                   NSLog(@"即将处理sources事件");
                                                                               }
                                                                                   break;

                                                                               case kCFRunLoopBeforeWaiting:
                                                                               {
                                                                                   NSLog(@"即将进入睡眠");
                                                                               }
                                                                                   break;

                                                                               case kCFRunLoopAfterWaiting:
                                                                               {
                                                                                   NSLog(@"被唤醒");
                                                                               }
                                                                                   break;

                                                                               case kCFRunLoopExit:
                                                                               {
                                                                                   NSLog(@"runloop退出");
                                                                               }
                                                                                   break;                                                                               default:
                                                                                   break;
                                                                           }
                                                                           
                                                                       });
    
    //给当前的runloop的kCFRunLoopCommonModes 这种模式添加监听者
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
    
}

/**
 runloop 的运行模式
 */
- (void)p_RunLoopMode{
    
    [self.view addSubview:self.textView];
    
    //1 这种方式创建的timer不会自动添加都当前的runlooop中，需要手动添加到当前的runloop
    NSTimer *timer1 = [NSTimer timerWithTimeInterval:.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"1111~~~~~~~~~~");
    }];
    [[NSRunLoop currentRunLoop]addTimer:timer1 forMode: NSDefaultRunLoopMode];
    //如果想要在textview滚动的时候定时的仍然正常运行，则需要将定时器也添加到当前runloop的 UITrackingRunLoopMode模式下
    [[NSRunLoop currentRunLoop] addTimer:timer1 forMode: UITrackingRunLoopMode];
    // 上面两句等同于下面一句
    [[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSRunLoopCommonModes];

    //2 这种方式创建的timer，会创建timer 并且将timer添加到当前的runloop当前的runloop（kCFRunLoopDefaultMode）
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
         NSLog(@"000~~~~~~~~~~");
    }];
   // textView 正在滚动的时候当前runloop对的运行模式是UITackingRunLoopMode 所以要将timer添加到这个mode中
   [[NSRunLoop currentRunLoop] addTimer:timer forMode: UITrackingRunLoopMode];
   
 

    // 3 如果在子线程中创建timer
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
            NSLog(@"000~~~~~~~~~~");
        }];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        // 子线程的runloop默认没有创建，所以需要创建子线程的runloop并且启动
        [[NSRunLoop currentRunLoop] run];
    });
    
    // 4 GCD中创建timer的方式 （GCD的定时器 ，精准度更高，不收runloop 运行模式的影响）
    // 4.1 创建gcd 中的定时器  参数：dispatchQueue  决定定时器中的任务在哪个线程中执行
    dispatch_source_t gcdTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    // 4.2 设置定时器的起始时间 | 间隔时间 | 精确度
    dispatch_source_set_timer(gcdTimer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    // 4.3 设置定时器应该执行的任务
    dispatch_source_set_event_handler(gcdTimer, ^{
        NSLog(@"GCD~~~~timer~~~~~%@",[NSThread currentThread]);
    });
    // 4.4 启动执行
    dispatch_resume(gcdTimer);
  
}




/**
 runloop 与 thread 之间的联系
 */
-(void)p_RunLoopWithThread{
    
    // 1 获得主线程对应的runloop
    NSRunLoop *mainLoop = [NSRunLoop mainRunLoop];
    
    // 2 获得当先线程对应的runloop
    NSRunLoop *currentLoop = [NSRunLoop currentRunLoop];
    
//    NSLog(@"mainLoop %@",mainLoop);
//    NSLog(@"currentLoop %@",currentLoop);
    
    // 子线程的runloop默认是没有创建的，currentRunloop这个方法是懒加载的，在调用这个方法的时候就会创建子线程的runloop
    NSThread *testThread =   [[NSThread alloc]initWithBlock:^{
         NSLog(@"%@",[NSRunLoop currentRunLoop]);
    }];
    
    [testThread start];
    
}
#pragma mark - lazyload
-(UITextView *)textView{
    if (!_textView) {
        _textView = [[UITextView alloc]init];
        _textView.backgroundColor = [UIColor orangeColor];
        _textView.frame = CGRectMake(100, 100, 100, 100);
        _textView.editable = NO;
        _textView.text = @"形散神聚：”形散“既指题材广泛、写法多样，又指结构自由、不拘一格；“神聚”既指中心集中，又指有贯穿全文的线索。散文写人写事都只是表面现象，从根本上说写的是情感体验。情感体验就是“不散的神”，而人与事则是“散”的可有可无、可多可少的“形”。“形散”主要是说散文取材十分广泛自由，不受时间和空间的限制；表现手法不拘一格：可以叙述事件的发展，可以描写人物形象，可以托物抒情，可以发表议论，而且作者可以根据内容需要自由调整、随意变化。“神不散”主要是从散文的立意方面说的，即散文所要表达的主题必须明确而集中，无论散文的内容多么广泛，表现手法多么灵活，无不为更好的表达主题服务。意境深邃：注重表现作者的生活感受，抒情性强，情感真挚。作者借助想象与联想，由此及彼，由浅入深，由实而虚的依次写";
        _textView.delegate = self;
    }
    return _textView;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    
}


@end
